import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { AstTree } from './ast-tree';
import { By } from '@angular/platform-browser';

describe('AstTree', () => {
  let component: AstTree;
  let fixture: ComponentFixture<AstTree>;
  let httpMock: HttpTestingController;

  const mockAst = {
    type: 'root',
    name: 'Root',
    children: [
      { type: 'child', name: 'Child 1', children: [] },
      { type: 'child', name: 'Child 2', children: [
        { type: 'leaf', name: 'Leaf', children: [] }
      ] }
    ]
  };

  beforeEach(waitForAsync(() => {
    TestBed.configureTestingModule({
      imports: [AstTree, HttpClientTestingModule]
    }).compileComponents();
    fixture = TestBed.createComponent(AstTree);
    component = fixture.componentInstance;
    httpMock = TestBed.inject(HttpTestingController);
  }));

  afterEach(() => {
    httpMock.verify();
  });

  it('should create', () => {
    fixture.detectChanges();
    expect(component).toBeTruthy();
  });

  it('should load and render AST tree', () => {
    fixture.detectChanges();
    const req = httpMock.expectOne('assets/output.json');
    req.flush(mockAst);
    fixture.detectChanges();
    const rootNode = fixture.debugElement.query(By.css('.tree-root'));
    expect(rootNode).toBeTruthy();
    expect(rootNode.nativeElement.textContent).toContain('Root');
    expect(rootNode.nativeElement.textContent).toContain('Child 1');
    expect(rootNode.nativeElement.textContent).toContain('Child 2');
  });

  it('should show loading and error states', () => {
    fixture.detectChanges();
    expect(fixture.nativeElement.textContent).toContain('加载中');
    const req = httpMock.expectOne('assets/output.json');
    req.error(new ErrorEvent('Network error'));
    fixture.detectChanges();
    expect(fixture.nativeElement.textContent).toContain('无法加载 output.json');
  });

  it('should expand/collapse nodes and show details', () => {
    fixture.detectChanges();
    const req = httpMock.expectOne('assets/output.json');
    req.flush(mockAst);
    fixture.detectChanges();
    // 展开 root
    const rootNode = component.ast()!;
    component.toggle(rootNode);
    fixture.detectChanges();
    // 展开 Child 2
    const child2 = rootNode.children![1];
    component.toggle(child2);
    fixture.detectChanges();
    // 选中 Leaf
    const leaf = child2.children![0];
    const event = new MouseEvent('click');
    component.select(leaf, event);
    fixture.detectChanges();
    expect(component.selectedNode()).toBe(leaf);
    expect(fixture.nativeElement.textContent).toContain('Leaf');
    expect(fixture.nativeElement.textContent).toContain('节点详情');
  });
});
